<?php
class HtmlCutString{
  function __construct($string, $limit){
    // create dom element using the html string
    $this->tempDiv = new DomDocument;
    $string = '<div>'.str_replace('&', '&amp;', html_entity_decode($string, ENT_QUOTES, 'UTF-8')).'</div>';
    $this->tempDiv->loadXML($string);
    // keep the characters count till now
    $this->charCount = 0;
    $this->encoding = 'UTF-8';
    // character limit need to check
    $this->limit = $limit;		
		$this->ellipsis = '...';
		$this->word_boundary = true;
		$this->html = true;
  }
  function cut(){
    // create empty document to store new html
    $this->newDiv = new DomDocument;
    // cut the string by parsing through each element
    $this->searchEnd($this->tempDiv->documentElement, $this->newDiv);
    $newhtml = $this->newDiv->saveHTML();
    return $newhtml;
  }

  function deleteChildren($node) {
    while (isset($node->firstChild)) {
      $this->deleteChildren($node->firstChild);
      $node->removeChild($node->firstChild);
    }
  } 
  function searchEnd($parseDiv, $newParent){
    foreach($parseDiv->childNodes as $ele){
			// not text node
			if($ele->nodeType != 3){
				$newEle = $this->newDiv->importNode($ele,true);
				if(count($ele->childNodes) === 0){
					$newParent->appendChild($newEle);
					continue;
				}
				$this->deleteChildren($newEle);
				$newParent->appendChild($newEle);
				$res = $this->searchEnd($ele,$newEle);
				if($res)
					return $res;
				else{
					continue;
				}
			}

			// the limit of the char count reached
			if(mb_strlen($ele->nodeValue,$this->encoding) + $this->charCount >= $this->limit){
				$newEle = $this->newDiv->importNode($ele);
				$limit = $this->limit - $this->charCount;
				if(function_exists('views_trim_text')){
					$newEle->nodeValue = views_trim_text(array(
							'max_length' => $limit, 
							'html' => $this->html, 
							'word_boundary' => $this->word_boundary, 
							'ellipsis' => $this->ellipsis, 
						), $newEle->nodeValue);
				} else {
					$newEle->nodeValue = cn_substr($newEle->nodeValue, 0, $limit);
				}
				$newParent->appendChild($newEle);
				return true;
			}
			$newEle = $this->newDiv->importNode($ele);
			$newParent->appendChild($newEle);
			$this->charCount += mb_strlen($newEle->nodeValue, $this->encoding);
    }
    return false;
  }
}


function cn_substr($sourcestr, $cutlength) {
    $returnstr = '';
    $i = 0;
    $n = 0;
    $str_length = strlen($sourcestr);
    while (($n < $cutlength) and ($i <= $str_length)) {
        $temp_str = substr($sourcestr, $i, 1);
        $ascnum = Ord($temp_str);
        //if ASCII bit > 224
        if ($ascnum >= 224) {
            $returnstr = $returnstr . substr($sourcestr, $i, 3);
            $i = $i + 3;
            $n++;
        } elseif ($ascnum >= 192) {
            $returnstr = $returnstr . substr($sourcestr, $i, 2);
            $i = $i + 2;
            $n++;
        } elseif ($ascnum >= 65 && $ascnum <= 90) {
            $returnstr = $returnstr . substr($sourcestr, $i, 1);
            $i = $i + 1;
            $n++;
        } else {
            $returnstr = $returnstr . substr($sourcestr, $i, 1);
            $i = $i + 1;
            $n = $n + 0.5;
        }
    }
    if ($sourcestr != $returnstr) {
        $returnstr = $returnstr;
    }
    return $returnstr;
}

/*class HtmlCutString{
  function __construct($string, $limit){
    // create dom element using the html string
    $this->tempDiv = new DomDocument;
    $this->tempDiv->loadXML('<div>'.$string.'</div>');
    // keep the characters count till now
    $this->charCount = 0;
    $this->encoding = 'UTF-8';
    // character limit need to check
    $this->limit = $limit;
  }
  function cut(){
    // create empty document to store new html
    $this->newDiv = new DomDocument;
    // cut the string by parsing through each element
    $this->searchEnd($this->tempDiv->documentElement,$this->newDiv);
    $newhtml = $this->newDiv->saveHTML();
    return $newhtml;
  }

  function deleteChildren($node) {
    while (isset($node->firstChild)) {
      $this->deleteChildren($node->firstChild);
      $node->removeChild($node->firstChild);
    }
  } 
  function searchEnd($parseDiv, $newParent){
    foreach($parseDiv->childNodes as $ele){
	// not text node
	if($ele->nodeType != 3){
	  $newEle = $this->newDiv->importNode($ele,true);
	  if(count($ele->childNodes) === 0){
	    $newParent->appendChild($newEle);
	    continue;
	  }
	  $this->deleteChildren($newEle);
	  $newParent->appendChild($newEle);
	    $res = $this->searchEnd($ele,$newEle);
	    if($res)
		return $res;
	    else{
		continue;
	    }
	}

	// the limit of the char count reached
	if(mb_strlen($ele->nodeValue,$this->encoding) + $this->charCount >= $this->limit){
	  $newEle = $this->newDiv->importNode($ele);
	    $newEle->nodeValue = substr($newEle->nodeValue,0, $this->limit - $this->charCount);
	    $newParent->appendChild($newEle);
	    return true;
	}
	$newEle = $this->newDiv->importNode($ele);
	$newParent->appendChild($newEle);
	$this->charCount += mb_strlen($newEle->nodeValue,$this->encoding);
    }
    return false;
  }
}*/

function cut_html_string($string, $limit, $ellipsis = '...', $word_boundary = true, $html = true){
  $cutting = new HtmlCutString($string, $limit);
	$cutting->ellipsis = $ellipsis;
	$cutting->word_boundary = $word_boundary;
	$cutting->html = $html;
  return $cutting->cut();
}

?>